﻿using Castle.MicroKernel;
using Castle.MicroKernel.Registration;
using Castle.Windsor;

namespace DreamDriven.ObjectModel
{
    public class ServiceLocator
    {
        private static volatile ServiceLocator _instance;
        private static readonly object Sync = new object();

        /// <summary>
        /// Use in case when ServiceLocator will be used before any client request.
        /// For example in Wcf server application.
        /// </summary>
        public static void Init()
        {
            _instance = new ServiceLocator();            
        }

        internal IWindsorContainer ServiceContainer { get; private set; }

        /// <summary>
        /// Application Aggregation Root
        /// </summary>
        internal static ServiceLocator Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (Sync)
                    {
                        if (_instance == null)
                        {
                            _instance = new ServiceLocator();
                        }
                    }
                }
                return _instance;
            }
        }

        internal TDomainModel GetDomainModel<TService, TDomainModel>()
            where TService : IDomainService
            where TDomainModel : IDomainModel
        {
            return (TDomainModel) ServiceContainer.Resolve(typeof(TService));
        }

        internal T GetComponent<T>()
        {
            return ServiceContainer.Resolve<T>();
        }

        internal T GetService<T>()
            where T : IDomainService
        {
            return ServiceContainer.Resolve<T>();
        }
       
        internal void Dispose()
        {
            ServiceContainer.Dispose();
        }

        private ServiceLocator()
        {
            ServiceContainer = new WindsorContainer("Services.xml");
            ServiceContainer.Kernel.ComponentModelBuilder.AddContributor(new MandatoryProperyInjectionContributor());
            ServiceContainer.Register(Component.For<IKernel>().Instance(ServiceContainer.Kernel));
            ServiceContainer.Register(Component.For<IWindsorContainer>().Instance(ServiceContainer));
        }
    }
}
